package com.example.archive.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.archive.entity.Archive;
import com.example.archive.entity.ArchiveDocument;
import com.example.archive.repository.elasticsearch.ArchiveDocumentRepository;
import com.example.archive.service.ArchiveService;
import com.example.archive.service.ElasticsearchArchiveService;
import com.example.archive.util.PageParam;
import com.example.archive.util.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * Elasticsearch档案搜索服务实现类
 * 提供基于Elasticsearch的高级搜索功能
 */
@Service
public class ElasticsearchArchiveServiceImpl implements ElasticsearchArchiveService {
    
    private static final Logger logger = LoggerFactory.getLogger(ElasticsearchArchiveServiceImpl.class);
    
    @Autowired
    private ArchiveDocumentRepository archiveDocumentRepository;
    
    @Autowired
    private ElasticsearchOperations elasticsearchOperations;
    
    @Autowired
    private ArchiveService archiveService;
    
    @Override
    public Result<Boolean> syncArchiveToElasticsearch(Archive archive) {
        try {
            if (archive == null || archive.getArchiveId() == null) {
                return Result.fail(400, "档案信息不能为空");
            }
            
            ArchiveDocument document = ArchiveDocument.fromArchive(archive);
            archiveDocumentRepository.save(document);
            
            logger.info("档案同步到Elasticsearch成功，ID: {}", archive.getArchiveId());
            return Result.success(true);
        } catch (Exception e) {
            logger.error("档案同步到Elasticsearch失败，ID: {}", archive.getArchiveId(), e);
            return Result.fail(500, "同步失败: " + e.getMessage());
        }
    }
    
    @Override
    public Result<Boolean> syncAllArchivesToElasticsearch() {
        try {
            // 获取所有档案
            List<Archive> archives = archiveService.list();
            
            // 转换为文档并批量保存
            List<ArchiveDocument> documents = archives.stream()
                    .map(ArchiveDocument::fromArchive)
                    .collect(Collectors.toList());
            
            archiveDocumentRepository.saveAll(documents);
            
            logger.info("批量同步档案到Elasticsearch成功，总数: {}", documents.size());
            return Result.success(true);
        } catch (Exception e) {
            logger.error("批量同步档案到Elasticsearch失败", e);
            return Result.fail(500, "批量同步失败: " + e.getMessage());
        }
    }
    
    @Override
    public Result<Boolean> deleteArchiveFromElasticsearch(Integer archiveId) {
        try {
            archiveDocumentRepository.deleteById(archiveId.toString());
            logger.info("从Elasticsearch删除档案成功，ID: {}", archiveId);
            return Result.success(true);
        } catch (Exception e) {
            logger.error("从Elasticsearch删除档案失败，ID: {}", archiveId, e);
            return Result.fail(500, "删除失败: " + e.getMessage());
        }
    }
    
    @Override
    public Result<IPage<Archive>> searchArchivesWithElasticsearch(PageParam pageParam, Integer userId) {
        try {
            Pageable pageable = PageRequest.of(
                    pageParam.getPageNum() - 1, 
                    pageParam.getPageSize()
            );
            
            org.springframework.data.domain.Page<ArchiveDocument> documentPage;
            
            if (pageParam.getSearch() == null || pageParam.getSearch().isEmpty()) {
                // 如果没有搜索关键词，返回所有可见的档案
                documentPage = archiveDocumentRepository.findAll(pageable);
            } else {
                // 使用多字段搜索，并考虑可见范围
                String userIdStr = userId != null ? userId.toString() : "";
                documentPage = archiveDocumentRepository.searchByMultipleFieldsWithVisibilityScope(
                        pageParam.getSearch(), userIdStr, pageable);
            }
            
            // 转换为Archive对象
            List<Archive> archives = documentPage.getContent().stream()
                    .map(this::convertToArchive)
                    .collect(Collectors.toList());
            
            // 构建分页结果
            Page<Archive> resultPage = new Page<>(pageParam.getPageNum(), pageParam.getPageSize());
            resultPage.setRecords(archives);
            resultPage.setTotal(documentPage.getTotalElements());
            
            logger.info("Elasticsearch搜索完成，关键词: {}, 结果数: {}", 
                       pageParam.getSearch(), archives.size());
            
            return Result.success(resultPage);
        } catch (Exception e) {
            logger.error("Elasticsearch搜索失败", e);
            return Result.fail(500, "搜索失败: " + e.getMessage());
        }
    }
    
    @Override
    public Result<IPage<Archive>> hybridSearch(PageParam pageParam, Integer userId) {
        // 首先尝试使用Elasticsearch搜索
        if (isElasticsearchAvailable()) {
            try {
                Result<IPage<Archive>> esResult = searchArchivesWithElasticsearch(pageParam, userId);
                if (esResult.getCode() == 200) {
                    logger.info("使用Elasticsearch搜索成功");
                    return esResult;
                }
            } catch (Exception e) {
                logger.warn("Elasticsearch搜索失败，回退到MySQL搜索", e);
            }
        }
        
        // 回退到MySQL搜索
        logger.info("回退到MySQL搜索");
        return archiveService.listArchives(pageParam, userId);
    }
    
    @Override
    public boolean isElasticsearchAvailable() {
        try {
            return elasticsearchOperations.indexOps(ArchiveDocument.class).exists();
        } catch (Exception e) {
            logger.warn("Elasticsearch连接检查失败", e);
            return false;
        }
    }
    
    /**
     * 将ArchiveDocument转换为Archive
     */
    private Archive convertToArchive(ArchiveDocument document) {
        // 这里可以从数据库重新查询完整的Archive对象
        // 或者直接转换（需要确保ArchiveDocument包含所有必要字段）
        return archiveService.getById(document.getArchiveId());
    }
} 